import macro from '@kitware/vtk.js/macro';
import vtkMatrixBuilder from '@kitware/vtk.js/Common/Core/MatrixBuilder';
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
// import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkArrowSource from '@kitware/vtk.js/Filters/Sources/ArrowSource';
import vtkCubeSource from '@kitware/vtk.js/Filters/Sources/CubeSource';
import vtkAppendPolyData from '@kitware/vtk.js/Filters/General/AppendPolyData';
// import { number } from 'vue-types';
import ImageHelper from '@kitware/vtk.js/Common/Core/ImageHelper';
import vtkTexture from '@kitware/vtk.js/Rendering/Core/Texture';
// ----------------------------------------------------------------------------
const FACE_TO_INDEX = {
  xPlus: 0,
  xMinus: 1,
  yPlus: 2,
  yMinus: 3,
  zPlus: 4,
  zMinus: 5,
};
const tmp = {
  text: 'x-',
  faceColor: '#7293DE',
  faceRotation: 0,
  fontFamily: 'Arial',
  fontColor: '#FFFFFF',
  fontStyle: 'normal',
  fontSizeScale: function fontSizeScale(resolution) {
    return resolution / 1.8;
  },
  edgeThickness: 0.1,
  edgeColor: 'black',
  resolution: 250,
};
function addColorb(ds, r, g, b) {
  const size = ds.getPoints().getData().length;
  const rgbArray = new Uint8Array(size);
  let offset = 0;

  while (offset < size) {
    rgbArray[offset++] = r;
    rgbArray[offset++] = g;
    rgbArray[offset++] = b;
  }

  ds.getPointData().setScalars(
    vtkDataArray.newInstance({
      name: 'color',
      numberOfComponents: 3,
      values: rgbArray,
    }),
  );
}

function centerDataSet(ds) {
  const bounds = ds.getPoints().getBounds();
  const center = [
    -(bounds[0] + bounds[1]) * 0.5,
    -(bounds[2] + bounds[3]) * 0.5,
    -(bounds[4] + bounds[5]) * 0.5,
  ];
  vtkMatrixBuilder
    .buildFromDegree()
    //@ts-ignore
    .translate(...center)
    .apply(ds.getPoints().getData());
}

// ----------------------------------------------------------------------------

function addColor(ds, r, g, b) {
  const size = ds.getPoints().getData().length;
  const rgbArray = new Uint8Array(size);
  let offset = 0;

  while (offset < size) {
    rgbArray[offset++] = r;
    rgbArray[offset++] = g;
    rgbArray[offset++] = b;
  }

  ds.getPointData().setScalars(
    vtkDataArray.newInstance({
      name: 'color',
      numberOfComponents: 3,
      values: rgbArray,
    }),
  );
}
// interface IModel {
//   xAxisColor: number;
//   yAxisColor: number;
//   zAxisColor: number;
// }
// ----------------------------------------------------------------------------
// vtkCustomAxesActor
// ----------------------------------------------------------------------------

function vtkCustomAxesActor(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkCustomAxesActor');

  // Make sure face properties are not references to the default value
  model.xPlusFaceProperty = { ...model.xPlusFaceProperty };
  model.xMinusFaceProperty = { ...model.xMinusFaceProperty };
  model.yPlusFaceProperty = { ...model.yPlusFaceProperty };
  model.yMinusFaceProperty = { ...model.yMinusFaceProperty };
  model.zPlusFaceProperty = { ...model.zPlusFaceProperty };
  model.zMinusFaceProperty = { ...model.zMinusFaceProperty };
  const canvas = document.createElement('canvas');
  const texture = vtkTexture.newInstance();
  texture.setInterpolate(true);
  function updateFaceTexture(faceName, newProp) {
    if (newProp) {
      Object.assign(model[`${faceName}FaceProperty`], newProp);
    }

    const prop = {
      ...model.defaultStyle,
      ...model[`${faceName}FaceProperty`],
    };

    // set canvas resolution
    canvas.width = prop.resolution;
    canvas.height = prop.resolution;

    const ctxt = canvas.getContext('2d');

    // set background color
    ctxt!.fillStyle = prop.faceColor;
    ctxt!.fillRect(0, 0, canvas.width, canvas.height);

    // draw edge
    if (prop.edgeThickness > 0) {
      ctxt!.strokeStyle = prop.edgeColor;
      ctxt!.lineWidth = prop.edgeThickness * canvas.width;
      ctxt!.strokeRect(0, 0, canvas.width, canvas.height);
    }

    // set face rotation
    ctxt!.save();

    // vertical flip
    ctxt!.translate(0, canvas.height);
    ctxt!.scale(1, -1);

    ctxt!.translate(canvas.width / 2, canvas.height / 2);
    ctxt!.rotate(-Math.PI * (prop.faceRotation / 180.0));

    // set foreground text
    const textSize = prop.fontSizeScale(prop.resolution);
    ctxt!.fillStyle = prop.fontColor;
    ctxt!.textAlign = 'center';
    ctxt!.textBaseline = 'middle';
    ctxt!.font = `${prop.fontStyle} ${textSize}px "${prop.fontFamily}"`;
    // ctxt!.fillText(prop.text, 0, 0);
    ctxt!.fillText('前', 0, 0);

    ctxt!.restore();

    const vtkImage = ImageHelper.canvasToImageData(canvas);
    texture.setInputData(vtkImage, FACE_TO_INDEX[faceName]);
    publicAPI.modified();
  }

  publicAPI.setXPlusFaceProperty = (prop) => updateFaceTexture('xPlus', prop);
  publicAPI.setXMinusFaceProperty = (prop) => updateFaceTexture('xMinus', prop);
  publicAPI.setYPlusFaceProperty = (prop) => updateFaceTexture('yPlus', prop);
  publicAPI.setYMinusFaceProperty = (prop) => updateFaceTexture('yMinus', prop);
  publicAPI.setZPlusFaceProperty = (prop) => updateFaceTexture('zPlus', prop);
  publicAPI.setZMinusFaceProperty = (prop) => updateFaceTexture('zMinus', prop);

  publicAPI.update = () => {
    const xAxis = vtkArrowSource
      .newInstance({ direction: [1, 0, 0], ...model.config, shaftLength: 3 })
      .getOutputData();
    centerDataSet(xAxis);
    //@ts-ignore
    addColor(xAxis, ...model.xAxisColor);

    const xAxisPts = xAxis.getPoints().getData();
    vtkMatrixBuilder.buildFromRadian().translate(0.55, 0.0, 0.0).apply(xAxisPts);

    const xAxis2 = vtkArrowSource
      .newInstance({ direction: [-1, 0, 0], ...model.config, shaftLength: 3 })
      .getOutputData();
    centerDataSet(xAxis2);
    //@ts-ignore
    addColor(xAxis2, ...model.xAxisColor);
    const xAxisPts2 = xAxis2.getPoints().getData();
    vtkMatrixBuilder.buildFromRadian().translate(-0.55, 0.5, 0.5).apply(xAxisPts2);

    const cubeSource = vtkCubeSource
      .newInstance({
        generate3DTextureCoordinates: true,
        xLength: 1,
        yLength: 1,
        zLength: 1,
      })
      .getOutputData();
    updateFaceTexture('xPlus', tmp);
    updateFaceTexture('xMinus', tmp);
    updateFaceTexture('yPlus', tmp);
    updateFaceTexture('yMinus', tmp);
    updateFaceTexture('zPlus', tmp);
    updateFaceTexture('zMinus', tmp);
    centerDataSet(cubeSource);
    addColorb(cubeSource, 114, 147, 222);
    const cubePts = cubeSource.getPoints().getData();
    vtkMatrixBuilder.buildFromRadian().translate(0.0, 0.0, 0.0).apply(cubePts);
    // set mapper
    // const mapper = vtkMapper.newInstance();
    // mapper.setInputConnection(cubeSource);

    const yAxis = vtkArrowSource
      .newInstance({ direction: [0, 1, 0], ...model.config })
      .getOutputData();
    centerDataSet(yAxis);
    //@ts-ignore
    addColor(yAxis, ...model.yAxisColor);

    const yAxisPts = yAxis.getPoints().getData();
    vtkMatrixBuilder.buildFromRadian().translate(0.5, 0.55, -0.5).apply(yAxisPts);

    const zAxis = vtkArrowSource
      .newInstance({ direction: [0, 0, 1], ...model.config })
      .getOutputData();
    centerDataSet(zAxis);
    //@ts-ignore
    addColor(zAxis, ...model.zAxisColor);

    const zAxisPts = zAxis.getPoints().getData();
    vtkMatrixBuilder.buildFromRadian().translate(0.5, 0.5, 0.55).apply(zAxisPts);

    function updateAllFaceTextures() {
      // cubeSource = vtkCubeSource.newInstance({
      //   generate3DTextureCoordinates: true,
      //   xLength: 1,
      //   yLength: 1,
      //   zLength: 1,
      // });
      // mapper.setInputConnection(cubeSource.getOutputPort());
    }
    publicAPI.setDefaultStyle = (style) => {
      console.log('entering publicAPI.setDefaultStyle', style);
      model.defaultStyle = { ...model.defaultStyle, ...style };
      updateAllFaceTextures();
    };

    const source = vtkAppendPolyData.newInstance();
    // source.setInputData(xAxis);
    source.addInputData(xAxis2);
    // source.setInputData(cubeSource);
    source.addInputData(cubeSource);
    source.addInputData(yAxis);
    source.addInputData(zAxis);

    // set mapper
    const mapper = vtkMapper.newInstance();
    mapper.setInputConnection(source.getOutputPort());
    publicAPI.setMapper(mapper);
    publicAPI.addTexture(texture);
  };

  publicAPI.update();

  // updateFaceTexture('xPlus', tmp);
  // updateFaceTexture('xMinus', tmp);
  // updateFaceTexture('yPlus', tmp);
  // updateFaceTexture('yMinus', tmp);
  // updateFaceTexture('zPlus', tmp);
  // updateFaceTexture('zMinus', tmp);
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

export const DEFAULT_VALUES = {
  defaultStyle: {
    text: 'xx',
    faceColor: 'white',
    faceRotation: 0,
    fontFamily: 'Arial',
    fontColor: 'white',
    fontStyle: 'normal',
    fontSizeScale: (resolution) => resolution / 1.8,
    edgeThickness: 0.1,
    edgeColor: 'black',
    resolution: 200,
  },
  config: {
    tipResolution: 60,
    tipRadius: 0.1,
    tipLength: 0.2,
    shaftResolution: 60,
    shaftRadius: 0.03,
    invert: false,
  },
  axisLabels: null,
  xAxisColor: [88, 124, 209],
  yAxisColor: [148, 212, 167],
  zAxisColor: [224, 141, 79],
  cubeColor: [244, 141, 33],
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  const maxWidth = 20;
  const totalHeight = 20;
  model.axisLabels = ['X', 'Y', 'Z'];
  model.tmCanvas = document.createElement('canvas');
  model.tmContext = model.tmCanvas.getContext('2d');
  model._tmAtlas = new Map(); // for texture atlas

  model.tmTexture = vtkTexture.newInstance();
  model.tmTexture.setInterpolate(false);
  model.tmCanvas.width = maxWidth;
  model.tmCanvas.height = totalHeight;
  model.tmContext.textBaseline = 'bottom';
  model.tmContext.textAlign = 'left';
  model.tmContext.clearRect(0, 0, maxWidth, totalHeight); // draw the text onto the texture

  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Inheritance
  vtkActor.extend(publicAPI, model, initialValues);

  macro.setGet(publicAPI, model, ['config']);
  macro.get(publicAPI, model, [
    'defaultStyle',
    'xPlusFaceProperty',
    'xMinusFaceProperty',
    'yPlusFaceProperty',
    'yMinusFaceProperty',
    'zPlusFaceProperty',
    'zMinusFaceProperty',
  ]); // Object methods

  macro.setGetArray(
    publicAPI,
    model,
    ['xAxisColor', 'yAxisColor', 'zAxisColor', 'cubeColor'],
    3,
    255,
  );

  // Object methods
  vtkCustomAxesActor(publicAPI, model);
  console.log('model::::', model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkCustomAxesActor');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
